package ru.spb.osll.myfit.client.widget;

import java.util.Vector;

import ru.spb.osll.myfit.client.PageMode;
import ru.spb.osll.myfit.common.PageElementType;
import ru.spb.osll.myfit.common.Table;
import ru.spb.osll.myfit.common.TableCell;
import ru.spb.osll.myfit.common.TableCellResult;
import ru.spb.osll.myfit.common.TableStyle;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.TextBox;

public abstract class TableWidget extends PageElementWidget {

  protected int m_selectedRow = -1;
  protected MyFlexTable m_flexTable;// = new FlexTable();
  protected int m_currentCell;
  private TableStyle m_tableStyle;

  protected MenuItem m_deleteRowItem;
  protected MenuItem m_addRowItem;
  // protected MenuItem m_deleteCellItem;
  protected MenuItem m_addCellItem;

  /**
   * Mode: edit/view
   */

  abstract protected void addRow(int row, Vector<TableCell> data);

  abstract protected void addNewRow(int row);

  abstract protected void addNewCell(int row, int cell);

  abstract protected void deleteCell(int row, int cell);

  abstract protected void changeWidth(TextBox tb, int displace);

  abstract protected void refreshTable(FlexTable table);

  abstract protected void setReadOnly(boolean isReadOnly);

  abstract protected void tuneMenu();

  Command deleteRowCommand = new Command() {
    public void execute() {
      m_rootPopupMenu.hide();
      if (m_selectedRow >= 0)
        m_flexTable.removeRow(m_selectedRow);
      if (m_flexTable.getRowCount() == 0) {
        removeFromParent();
        try {
          this.finalize();
        } catch (Throwable e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
  };

  Command addRowCommand = new Command() {
    public void execute() {
      m_rootPopupMenu.hide();
      if (m_selectedRow >= 0)
        addNewRow(m_selectedRow + 1);
    }
  };

  Command deleteCellCommand = new Command() {
    public void execute() {
      m_rootPopupMenu.hide();
      if (m_selectedRow >= 0 && m_currentCell >= 0) {
        deleteCell(m_selectedRow, m_currentCell);
      }
    }
  };

  Command addCellCommand = new Command() {
    public void execute() {
      m_rootPopupMenu.hide();
      if (m_selectedRow > 0 && m_currentCell >= 0) {
        addNewCell(m_selectedRow, m_currentCell + 1);
      }
    }
  };

  public TableWidget(GWTWidgetFactory gwtWidgetFactory, Table table) {
    super(gwtWidgetFactory);

    sinkEvents(Event.ONMOUSEUP | Event.ONDBLCLICK | Event.ONCONTEXTMENU);
    createPopupMenu();
    addCustomItemInMenu();

    setTableStyle(table.getStyle());
    m_flexTable = m_gwtWidgetFactory.createMyFlexTable();

    m_flexTable.setCellSpacing(0);
    m_flexTable.setCellPadding(0);

    m_flexTable.setStyleName("flexTableStyle");

    insertTable(table);
    Vector<Vector<TableCell>> data = table.getData();

    for (int i = 0; i < data.size(); ++i) {
      Vector<String> line = new Vector<String>();
      Vector<TableCell> cellLine = data.elementAt(i);
      for (int j = 0; j < cellLine.size(); j++)
        line.add(cellLine.get(j).getText());
      addRow(i, cellLine);
    }
    initWidget(m_flexTable);

  }

  private void addCustomItemInMenu() {
    m_rootMenuBar.addSeparator();

    m_deleteRowItem = m_gwtWidgetFactory.createMenuItem("Delete row", true,
        deleteRowCommand);
    m_addRowItem = m_gwtWidgetFactory.createMenuItem("Add row", true,
        addRowCommand);
    m_addCellItem = m_gwtWidgetFactory.createMenuItem("Add cell", true,
        addCellCommand);

    m_rootMenuBar.addItem(m_deleteRowItem);
    m_rootMenuBar.addItem(m_addRowItem);
    m_rootMenuBar.addItem(m_addCellItem);
  }

  protected TextBox createTextEdit(TableCell cell) {
    TextBox tb = new TextBox();

    String text = cell.getText();
    tb.setStyleName("tableCellStyle");
    if (cell.getTestResult().equals(TableCellResult.PASS))
      tb.setStyleName("tableCellPassStyle");
    else if (cell.getTestResult().equals(TableCellResult.FAIL))
      tb.setStyleName("tableCellFailStyle");
    else if (cell.getTestResult().equals(TableCellResult.EXCEPTION)) {
      tb.setStyleName("tableCellExecptionStyle");
      Tooltip tooltip = new Tooltip(cell.getTooltip());
      tb.addMouseListener(new TooltipMouseListener(tooltip));
    }

    int length = (text.trim()).length();
    int normLen = (length > 0) ? length : 1;
    tb.setVisibleLength(normLen);
    tb.setText(text.trim());

    tb.addKeyPressHandler(new KeyPressHandler() {
      @Override
      public void onKeyPress(KeyPressEvent event) {
        if (event.getCharCode() == KeyCodes.KEY_ESCAPE) {
          TextBox tb = (TextBox) event.getSource();
          HorizontalPanel parent = (HorizontalPanel) tb.getParent();
          tb.removeFromParent();
          if (parent.getWidgetCount() == 0)
            refreshTable((FlexTable) parent.getParent());
        } else if (event.getCharCode() == KeyCodes.KEY_BACKSPACE ||
            event.getCharCode() == KeyCodes.KEY_DELETE)
          changeWidth((TextBox) event.getSource(), -1);
        else if (event.getCharCode() > 47 || event.getCharCode() == 32)
          changeWidth(((TextBox) event.getSource()), 1);
      }
    });

    tb.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        m_currentCell = m_flexTable.getCellForEvent(event).getCellIndex();
        m_selectedRow = m_flexTable.getCellForEvent(event).getRowIndex();
      }
    });

    tb.addKeyUpHandler(new KeyUpHandler() {
      @Override
      public void onKeyUp(KeyUpEvent event) {
        changeWidth(((TextBox) event.getSource()), 0);
      }
    });

    return tb;
  }

  @Override
  protected void onRightClick(Event event) {
    super.onRightClick(event);
    if (m_mode.equals(PageMode.VIEW)) {
      return;
    }
    Element td = m_flexTable.getEventTargetCell(event);
    if (td == null) {
      m_selectedRow = -1;
    }
    m_currentCell = td.getChildCount();
    Element tr = DOM.getParent(td);
    Element body = DOM.getParent(tr);
    m_selectedRow = DOM.getChildIndex(body, tr);
    m_currentCell = DOM.getChildIndex(tr, td);
    GWT.log("selectedRow " + m_selectedRow);
    tuneMenu();
  }

  /**
   * Disable / enable cells of the widgets
   * 
   * @param mode
   */
  @Override
  public void setMode(PageMode mode) {
    boolean isReadOnly = true;
    switch (mode) {
    case EDIT:
      this.m_mode = PageMode.EDIT;
      isReadOnly = false;
      break;
    case VIEW:
      this.m_mode = PageMode.VIEW;
      isReadOnly = true;
      break;
    }
    setReadOnly(isReadOnly);
  }

  public void setTableStyle(TableStyle tableStyle) {
    m_tableStyle = tableStyle;
  }

  public TableStyle getTableStyle() {
    return m_tableStyle;
  }

  @Override
  public void setOpen(boolean isOpen) {
    // no action needed.
  }

  public static class MyFlexTable extends FlexTable {
    @Override
    public Element getEventTargetCell(Event arg0) {
      return super.getEventTargetCell(arg0);
    }
  }

  public void insertTable(Table table) {
    m_flexTable.removeAllRows();
    setTableStyle(table.getStyle());
    Vector<Vector<TableCell>> data = table.getData();

    for (int i = 0; i < data.size(); ++i) {
      Vector<String> line = new Vector<String>();
      Vector<TableCell> cellLine = data.elementAt(i);
      for (int j = 0; j < cellLine.size(); j++)
        line.add(cellLine.get(j).getText());
      addRow(i, cellLine);
    }
  }

  @Override
  public PageElementType getType() {
    return PageElementType.TABLE;
  }

}
